package com.lyl.mysqlmonitor.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import com.lyl.mysqlmonitor.callback.CallbackManager;
import com.lyl.mysqlmonitor.callback.IndexAnalysisCallback;

/**
 * MySQL索引监控配置类
 * 用于控制监控行为和日志级别
 */
public class MonitorConfig implements Serializable {
    private static final Logger LOGGER = LoggerFactory.getLogger(MonitorConfig.class);

    // 默认配置值
    public static final int DEFAULT_WARN_THRESHOLD = 1000; // 毫秒
    public static final int DEFAULT_ERROR_THRESHOLD = 5000; // 毫秒
    public static final boolean DEFAULT_LOG_SLOW_QUERIES = true;
    public static final int DEFAULT_SLOW_QUERY_THRESHOLD = 1000; // 毫秒

    // MySQL版本常量
    public static final int MYSQL_VERSION_5_7 = 57;
    public static final int MYSQL_VERSION_8_0 = 80;

    // 配置项
    private boolean enabled;
    private int warnThreshold;
    private int errorThreshold;
    private boolean logSlowQueries;
    private int slowQueryThreshold;
    private boolean printParameters = true;
    private boolean provideOptimizationTips = true;
    private boolean selectOnly = true;
    private boolean showDetailedAnalysis = false; // 是否显示详细的索引分析

    // 版本相关配置
    private int mysqlVersion = MYSQL_VERSION_8_0; // 默认假设为8.0
    private String compatibilityMode = "auto"; // 自动、5.7兼容、8.0兼容
    private boolean strictMode = false; // 严格模式下，使用不兼容特性会抛出异常

    // 自定义SQL检测规则列表
    private final List<Pattern> customSqlPatterns = new ArrayList<>();
    private boolean useCustomPatterns = false;

    // 忽略SQL检测规则列表
    private final List<Pattern> ignoreSqlPatterns = new ArrayList<>();
    private boolean useIgnorePatterns = false;

    // 回调管理器
    private CallbackManager callbackManager;

    private static volatile MonitorConfig instance;

    private MonitorConfig() {
        loadConfig();
    }

    /**
     * 获取配置实例
     * @return 配置实例
     */
    public static MonitorConfig getInstance() {
        if (instance == null) {
            synchronized (MonitorConfig.class) {
                if (instance == null) {
                    instance = new MonitorConfig();
                }
            }
        }
        return instance;
    }

    private void loadConfig() {
        // 从系统属性加载配置
        enabled = Boolean.parseBoolean(System.getProperty("mysql.monitor.enabled", "true"));
        warnThreshold = Integer.parseInt(System.getProperty("mysql.monitor.warn.threshold",
            String.valueOf(DEFAULT_WARN_THRESHOLD)));
        errorThreshold = Integer.parseInt(System.getProperty("mysql.monitor.error.threshold",
            String.valueOf(DEFAULT_ERROR_THRESHOLD)));
        logSlowQueries = Boolean.parseBoolean(System.getProperty("mysql.monitor.log.slow.queries",
            String.valueOf(DEFAULT_LOG_SLOW_QUERIES)));
        slowQueryThreshold = Integer.parseInt(System.getProperty("mysql.monitor.slow.query.threshold",
            String.valueOf(DEFAULT_SLOW_QUERY_THRESHOLD)));
        showDetailedAnalysis = Boolean.parseBoolean(System.getProperty("mysql.monitor.show.detailed.analysis", "false"));
        useCustomPatterns = Boolean.parseBoolean(System.getProperty("mysql.monitor.use.custom.patterns", "false"));
        useIgnorePatterns = Boolean.parseBoolean(System.getProperty("mysql.monitor.use.ignore.patterns", "false"));

        // 加载版本相关配置
        compatibilityMode = System.getProperty("mysql.monitor.compatibility.mode", "auto");
        strictMode = Boolean.parseBoolean(System.getProperty("mysql.monitor.strict.mode", "false"));

        LOGGER.info("Loaded configuration: enabled={}, warnThreshold={}, errorThreshold={}, " +
                   "logSlowQueries={}, slowQueryThreshold={}, compatibilityMode={}, strictMode={}, " +
                   "showDetailedAnalysis={}, useCustomPatterns={}, useIgnorePatterns={}",
                   enabled, warnThreshold, errorThreshold, logSlowQueries, slowQueryThreshold,
                   compatibilityMode, strictMode, showDetailedAnalysis, useCustomPatterns, useIgnorePatterns);
    }

    /**
     * 获取是否启用监控
     * @return 是否启用监控
     */
    public boolean isEnabled() {
        return enabled;
    }

    /**
     * 获取警告阈值
     * @return 警告阈值
     */
    public int getWarnThreshold() {
        return warnThreshold;
    }

    /**
     * 获取错误阈值
     * @return 错误阈值
     */
    public int getErrorThreshold() {
        return errorThreshold;
    }

    /**
     * 获取是否记录慢查询
     * @return 是否记录慢查询
     */
    public boolean isLogSlowQueries() {
        return logSlowQueries;
    }

    /**
     * 获取慢查询阈值
     * @return 慢查询阈值
     */
    public int getSlowQueryThreshold() {
        return slowQueryThreshold;
    }

    /**
     * 设置是否启用监控
     * @param enabled 是否启用监控
     */
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
        System.setProperty("mysql.monitor.enabled", String.valueOf(enabled));
    }

    /**
     * 设置警告阈值
     * @param warnThreshold 警告阈值
     */
    public void setWarnThreshold(int warnThreshold) {
        this.warnThreshold = warnThreshold;
        System.setProperty("mysql.monitor.warn.threshold", String.valueOf(warnThreshold));
    }

    /**
     * 设置错误阈值
     * @param errorThreshold 错误阈值
     */
    public void setErrorThreshold(int errorThreshold) {
        this.errorThreshold = errorThreshold;
        System.setProperty("mysql.monitor.error.threshold", String.valueOf(errorThreshold));
    }

    /**
     * 设置是否记录慢查询
     * @param logSlowQueries 是否记录慢查询
     */
    public void setLogSlowQueries(boolean logSlowQueries) {
        this.logSlowQueries = logSlowQueries;
        System.setProperty("mysql.monitor.log.slow.queries", String.valueOf(logSlowQueries));
    }

    /**
     * 设置慢查询阈值
     * @param slowQueryThreshold 慢查询阈值
     */
    public void setSlowQueryThreshold(int slowQueryThreshold) {
        this.slowQueryThreshold = slowQueryThreshold;
        System.setProperty("mysql.monitor.slow.query.threshold", String.valueOf(slowQueryThreshold));
    }

    /**
     * 重新加载配置
     */
    public void reload() {
        loadConfig();
    }

    /**
     * 是否打印参数值
     * @return 是否打印参数值
     */
    public boolean isPrintParameters() {
        return printParameters;
    }

    /**
     * 设置是否打印参数值
     * @param printParameters 是否打印参数值
     */
    public void setPrintParameters(boolean printParameters) {
        this.printParameters = printParameters;
    }

    /**
     * 是否提供优化建议
     * @return 是否提供优化建议
     */
    public boolean isProvideOptimizationTips() {
        return provideOptimizationTips;
    }

    /**
     * 设置是否提供优化建议
     * @param provideOptimizationTips 是否提供优化建议
     */
    public void setProvideOptimizationTips(boolean provideOptimizationTips) {
        this.provideOptimizationTips = provideOptimizationTips;
    }

    /**
     * 是否只监控SELECT语句
     * @return 是否只监控SELECT语句
     */
    public boolean isSelectOnly() {
        return selectOnly;
    }

    /**
     * 设置是否只监控SELECT语句
     * @param selectOnly 是否只监控SELECT语句
     */
    public void setSelectOnly(boolean selectOnly) {
        this.selectOnly = selectOnly;
    }

    /**
     * 获取当前MySQL版本
     * @return MySQL版本
     */
    public int getMysqlVersion() {
        return mysqlVersion;
    }

    /**
     * 设置当前MySQL版本
     * @param mysqlVersion MySQL版本
     */
    public void setMysqlVersion(int mysqlVersion) {
        this.mysqlVersion = mysqlVersion;
        LOGGER.info("设置MySQL版本为: {}.{}", mysqlVersion / 10, mysqlVersion % 10);
    }

    /**
     * 获取兼容模式
     * @return 兼容模式
     */
    public String getCompatibilityMode() {
        return compatibilityMode;
    }

    /**
     * 设置兼容模式
     * @param compatibilityMode 兼容模式，可选值：auto、5.7、8.0
     */
    public void setCompatibilityMode(String compatibilityMode) {
        if (!"auto".equals(compatibilityMode) && !"5.7".equals(compatibilityMode) && !"8.0".equals(compatibilityMode)) {
            throw new IllegalArgumentException("兼容模式必须是auto、5.7或8.0之一");
        }
        this.compatibilityMode = compatibilityMode;
        System.setProperty("mysql.monitor.compatibility.mode", compatibilityMode);
        LOGGER.info("设置兼容模式为: {}", compatibilityMode);
    }

    /**
     * 是否是严格模式
     * @return 是否是严格模式
     */
    public boolean isStrictMode() {
        return strictMode;
    }

    /**
     * 设置是否是严格模式
     * @param strictMode 是否是严格模式
     */
    public void setStrictMode(boolean strictMode) {
        this.strictMode = strictMode;
        System.setProperty("mysql.monitor.strict.mode", String.valueOf(strictMode));
        LOGGER.info("设置严格模式为: {}", strictMode);
    }

    /**
     * 检查是否是MySQL 5.7兼容模式
     * @return 如果是5.7模式返回true，否则返回false
     */
    public boolean isMySQL57Mode() {
        if ("5.7".equals(compatibilityMode)) {
            return true;
        }
        if ("auto".equals(compatibilityMode)) {
            return mysqlVersion == MYSQL_VERSION_5_7;
        }
        return false;
    }

    /**
     * 检查是否是MySQL 8.0兼容模式
     * @return 如果是8.0模式返回true，否则返回false
     */
    public boolean isMySQL80Mode() {
        if ("8.0".equals(compatibilityMode)) {
            return true;
        }
        if ("auto".equals(compatibilityMode)) {
            return mysqlVersion == MYSQL_VERSION_8_0;
        }
        return false;
    }

    /**
     * 获取当前MySQL版本的字符串表示
     * @return 版本字符串
     */
    public String getMysqlVersionString() {
        return String.format("%d.%d", mysqlVersion / 10, mysqlVersion % 10);
    }

    /**
     * 是否显示详细的索引分析
     * @return 是否显示详细的索引分析
     */
    public boolean isShowDetailedAnalysis() {
        return showDetailedAnalysis;
    }

    /**
     * 设置是否显示详细的索引分析
     * @param showDetailedAnalysis 是否显示详细的索引分析
     */
    public void setShowDetailedAnalysis(boolean showDetailedAnalysis) {
        this.showDetailedAnalysis = showDetailedAnalysis;
        System.setProperty("mysql.monitor.show.detailed.analysis", String.valueOf(showDetailedAnalysis));
    }

    /**
     * 设置索引分析回调接口
     * @param callback 索引分析回调接口
     */
    public void setCallback(IndexAnalysisCallback callback) {
        this.callbackManager = new CallbackManager(callback);
    }

    /**
     * 获取回调管理器
     * @return 回调管理器
     */
    public CallbackManager getCallbackManager() {
        return callbackManager;
    }

    /**
     * 检查是否设置了回调接口
     * @return 如果设置了回调接口返回true
     */
    public boolean hasCallback() {
        return callbackManager != null && callbackManager.hasCallback();
    }

    /**
     * 获取自定义SQL检测规则列表
     * @return 自定义SQL检测规则列表
     */
    public List<Pattern> getCustomSqlPatterns() {
        return customSqlPatterns;
    }

    /**
     * 添加自定义SQL检测规则
     * @param pattern 正则表达式模式
     */
    public void addCustomSqlPattern(String pattern) {
        Pattern compiledPattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE);
        customSqlPatterns.add(compiledPattern);
        LOGGER.info("添加自定义SQL检测规则: {}", pattern);
    }

    /**
     * 添加自定义SQL检测规则（带标志）
     * @param pattern 正则表达式模式
     * @param flags 编译标志
     */
    public void addCustomSqlPattern(String pattern, int flags) {
        Pattern compiledPattern = Pattern.compile(pattern, flags);
        customSqlPatterns.add(compiledPattern);
        LOGGER.info("添加自定义SQL检测规则(带标志): {}", pattern);
    }

    /**
     * 清除所有自定义SQL检测规则
     */
    public void clearCustomSqlPatterns() {
        customSqlPatterns.clear();
        LOGGER.info("清除所有自定义SQL检测规则");
    }

    /**
     * 检查SQL是否匹配任何自定义规则
     * @param sql SQL语句
     * @return 如果匹配返回true，否则返回false
     */
    public boolean matchesCustomPatterns(String sql) {
        if (!useCustomPatterns || customSqlPatterns.isEmpty()) {
            return false;
        }

        for (Pattern pattern : customSqlPatterns) {
            if (pattern.matcher(sql).find()) {
                return true;
            }
        }

        return false;
    }

    /**
     * 获取是否使用自定义SQL检测规则
     * @return 是否使用自定义SQL检测规则
     */
    public boolean isUseCustomPatterns() {
        return useCustomPatterns;
    }

    /**
     * 设置是否使用自定义SQL检测规则
     * @param useCustomPatterns 是否使用自定义SQL检测规则
     */
    public void setUseCustomPatterns(boolean useCustomPatterns) {
        this.useCustomPatterns = useCustomPatterns;
        System.setProperty("mysql.monitor.use.custom.patterns", String.valueOf(useCustomPatterns));
        LOGGER.info("设置是否使用自定义SQL检测规则: {}", useCustomPatterns);
    }

    /**
     * 获取忽略SQL检测规则列表
     * @return 忽略SQL检测规则列表
     */
    public List<Pattern> getIgnoreSqlPatterns() {
        return ignoreSqlPatterns;
    }

    /**
     * 添加忽略SQL检测规则
     * @param pattern 正则表达式模式
     */
    public void addIgnoreSqlPattern(String pattern) {
        Pattern compiledPattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE);
        ignoreSqlPatterns.add(compiledPattern);
        LOGGER.info("添加忽略SQL检测规则: {}", pattern);
    }

    /**
     * 添加忽略SQL检测规则（带标志）
     * @param pattern 正则表达式模式
     * @param flags 编译标志
     */
    public void addIgnoreSqlPattern(String pattern, int flags) {
        Pattern compiledPattern = Pattern.compile(pattern, flags);
        ignoreSqlPatterns.add(compiledPattern);
        LOGGER.info("添加忽略SQL检测规则(带标志): {}", pattern);
    }

    /**
     * 清除所有忽略SQL检测规则
     */
    public void clearIgnoreSqlPatterns() {
        ignoreSqlPatterns.clear();
        LOGGER.info("清除所有忽略SQL检测规则");
    }

    /**
     * 检查SQL是否匹配任何忽略规则
     * @param sql SQL语句
     * @return 如果匹配返回true，表示该SQL应被忽略不检测
     */
    public boolean matchesIgnorePatterns(String sql) {
        if (!useIgnorePatterns || ignoreSqlPatterns.isEmpty()) {
            return false;
        }

        for (Pattern pattern : ignoreSqlPatterns) {
            if (pattern.matcher(sql).find()) {
                return true;
            }
        }

        return false;
    }

    /**
     * 是否使用忽略SQL检测规则
     * @return 是否使用忽略SQL检测规则
     */
    public boolean isUseIgnorePatterns() {
        return useIgnorePatterns;
    }

    /**
     * 设置是否使用忽略SQL检测规则
     * @param useIgnorePatterns 是否使用忽略SQL检测规则
     */
    public void setUseIgnorePatterns(boolean useIgnorePatterns) {
        this.useIgnorePatterns = useIgnorePatterns;
        System.setProperty("mysql.monitor.use.ignore.patterns", String.valueOf(useIgnorePatterns));
        LOGGER.info("设置是否使用忽略SQL检测规则: {}", useIgnorePatterns);
    }
}
